package com.vichat.common.util;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class HttpSend {

    private static Logger logger = LoggerFactory.getLogger(HttpSend.class);

    public static String json(String url, Object obj) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost method = new HttpPost(url);
        String responseBody = null;
        try {
            // 建立一个NameValuePair数组，用于存储欲传送的参数
            method.addHeader("Content-type", "application/json; charset=utf-8");
            method.setHeader("Accept", "application/json");
            String json = CommonUtil.toJson(obj);
            method.setEntity(new StringEntity(json, Charset.forName("UTF-8")));
            long startTime = System.currentTimeMillis();
            HttpResponse response = httpClient.execute(method);
            long endTime = System.currentTimeMillis();
            int statusCode = response.getStatusLine().getStatusCode();
            logger.error("输入参数：" + url + "\t" + json + "\tstatusCode:" + statusCode + "\ttime(ms):" + (endTime - startTime));
            if (statusCode != HttpStatus.SC_OK) {
                logger.error("Method failed:" + response.getStatusLine());
            }
            // Read the response body
            responseBody = EntityUtils.toString(response.getEntity());
            logger.error("http response body： " + responseBody);
        } catch (IOException e) {
            logger.error("网络错误", e);
        }
        return responseBody;
    }


    public static String get(String url, String data) {
        Map<String, Object> parameterMap = new HashMap<>();
        parameterMap.put("data", data);
        return get(url, parameterMap);
    }

    public static String get(String url, Map<String, Object> parameterMap) {
        String result = null;
        HttpClient httpClient = new DefaultHttpClient();
        try {
            List<NameValuePair> nameValuePairs = getNameValuePairs(parameterMap);
            String uri = url + (StringUtils.contains(url, "?") ? "&" : "?") + EntityUtils.toString(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
            logger.info(uri);
            HttpGet httpGet = new HttpGet(uri);
            HttpResponse httpResponse = httpClient.execute(httpGet);
            HttpEntity httpEntity = httpResponse.getEntity();
            result = EntityUtils.toString(httpEntity, "UTF-8");
            EntityUtils.consume(httpEntity);
            logger.info("http response body： " + result);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(httpClient);
        }
        return result;
    }

    public static String post(String url, Map<String, Object> parameterMap) {
        String result = null;
        HttpClient httpClient = new DefaultHttpClient();
        try {
            result = doService(url, parameterMap, httpClient);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(httpClient);
        }
        return result;
    }

    public static String postString(String url, String data) {
        String result = null;
        HttpClient httpClient = new DefaultHttpClient();
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(new StringEntity(data, "UTF-8"));
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            result = EntityUtils.toString(httpEntity, "UTF-8");
            EntityUtils.consume(httpEntity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(httpClient);
        }
        return result;
    }

    public static String postHttpsWithoutCart(String url, Map<String, Object> parameterMap) {
        String result = null;
        HttpClient httpClient = new DefaultHttpClient();
        try {
            httpClient = wrapClient(httpClient);
            result = doService(url, parameterMap, httpClient);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(httpClient);
        }
        return result;
    }

    public static String postWithPCKS12(String url, Map<String, Object> parameterMap, File file, String pwd) {
        String result = null;
        HttpClient httpClient = new DefaultHttpClient();
        try {
            httpClient = needCarClient(httpClient, file, pwd);
            result = doService(url, parameterMap, httpClient);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(httpClient);
        }
        return result;
    }

    public static String postWithPCKS12(String url, Object o, File file, String pwd) {
        String result = null;
        HttpClient httpClient = new DefaultHttpClient();
        try {
            httpClient = needCarClient(httpClient, file, pwd);
            HttpPost httpPost = new HttpPost(url);
            StringEntity stringEntity = new StringEntity(o.toString(), "UTF-8");
            httpPost.setEntity(stringEntity);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            result = EntityUtils.toString(httpEntity, "UTF-8");
            EntityUtils.consume(httpEntity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(httpClient);
        }
        return result;
    }

    private static HttpClient needCarClient(HttpClient base, File file, String pwd) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream inStream = new FileInputStream(file)) {
            keyStore.load(inStream, pwd.toCharArray());
        }
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, pwd.toCharArray());
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), null, null);
        SSLSocketFactory ssf = new SSLSocketFactory(sslContext);
        ssf.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        ClientConnectionManager ccm = base.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", ssf, 443));
        return new DefaultHttpClient(ccm, base.getParams());
    }

    private static HttpClient wrapClient(HttpClient base) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs, String string) {
                }

                public void checkServerTrusted(X509Certificate[] xcs, String string) {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = base.getConnectionManager();
            SchemeRegistry sr = ccm.getSchemeRegistry();
            sr.register(new Scheme("https", ssf, 443));
            return new DefaultHttpClient(ccm, base.getParams());
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    private static String doService(String url, Map<String, Object> parameterMap, HttpClient httpClient) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nameValuePairs = getNameValuePairs(parameterMap);
        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        String result = EntityUtils.toString(httpEntity, "UTF-8");
        EntityUtils.consume(httpEntity);
        return result;
    }

    private static List<NameValuePair> getNameValuePairs(Map<String, Object> parameterMap) {
        List<NameValuePair> nameValuePairs = new ArrayList<>();
        if (parameterMap != null) {
            for (Entry<String, Object> entry : parameterMap.entrySet()) {
                String name = entry.getKey();
                String value = ConvertUtils.convert(entry.getValue());
                if (StringUtils.isNotEmpty(name)) {
                    nameValuePairs.add(new BasicNameValuePair(name, value));
                }
            }
        }
        return nameValuePairs;
    }

    private static void close(CloseableHttpClient httpClient) {
        if (httpClient == null) return;
        try {
            httpClient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void close(HttpClient httpClient) {
        if (httpClient == null) return;
        try {
            httpClient.getConnectionManager().shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
